﻿/**
**		File : pak_kernel_common.cpp
**		Author : beyondcode
**		Date : 2010/06/22
**		Des : beyondpak 通用平台核心
**
**/

#include "pak_kernel_common.h"
#include "debugheader.h"
#include <stdio.h>

PPAK_DIR _CreatePakDir()
{
	PPAK_DIR psPakDirNew	=	NULL;

	psPakDirNew = calloc( 1, sizeof( PAK_DIR ) );
	if ( !psPakDirNew )
		return psPakDirNew;

	if ( !_InitDir( psPakDirNew ) )
	{
		_DestroyPakDir( psPakDirNew );
		psPakDirNew = NULL;
	}

	return psPakDirNew;
}
int _DestroyPakDir( PPAK_DIR psPakDir )
{
	if ( psPakDir )
	{
		_ReleaseDir( psPakDir );
		free( psPakDir );
		psPakDir = NULL;
	}

	return 1;
}
int _InitDir( PPAK_DIR pPakDir )
{
	if( !pPakDir )
		return 0;

	memset( pPakDir, 0, sizeof(PAK_DIR) );
	pPakDir->nType = DIRTYPE_DIR;
	return 1;
}
int _ClearDir( PPAK_DIR pPakDir )
{
	if( !pPakDir )
		return 0;
	
	if( _CheckDir( pPakDir ) )
	{
		memset( pPakDir->pszName, 0, pPakDir->nNameLen );
		pPakDir->nType = DIRTYPE_DIR;
	}
	return 1;
}

int _CopyDir( PPAK_DIR pPakSrcDir, PPAK_DIR pPakDestDir )
{
	if( !pPakSrcDir || !pPakDestDir )
		return 0;
	
	if( !_CheckDir( pPakSrcDir ) )
		return 0;

	pPakDestDir->nType = pPakSrcDir->nType;
	if( !_SetDirName( pPakDestDir, pPakSrcDir->pszName ) )
		return 0;
	return 1;
}

int _SetDirName( PPAK_DIR pPakDestDir, const char* pszDirName )
{
	size_t nDirNameLen = 0;

	if( !pPakDestDir || !pszDirName )
		return 0;
	
	nDirNameLen = strlen( pszDirName ) + 1;
	if( _GetDirBufferLen( pPakDestDir ) < nDirNameLen )
	{
		if( !_MallocDir( pPakDestDir, nDirNameLen ) )
			return 0;
	}
	
	strcpy( pPakDestDir->pszName, pszDirName );

	return 1;
}

int _SetDirType( PPAK_DIR pDirDest, int nType )
{
	if( !pDirDest )
		return 0;
	pDirDest->nType = nType;
	return 1;
}

int _ReleaseDir( PPAK_DIR pPakDir )
{
	if( !pPakDir )
		return 0;
	if( pPakDir->pszName )
	{
		free( pPakDir->pszName );
	}
	memset( pPakDir, 0, sizeof(PAK_DIR) );
	return 1;
}

int _MallocDir( PPAK_DIR pPakDir, size_t nNameLen )
{
	if( !pPakDir )
		return 0;
	
	if( pPakDir->nNameLen < nNameLen )
	{
		_ReleaseDir( pPakDir );
		pPakDir->pszName = (char*)malloc( nNameLen );
		if( !pPakDir->pszName )
			return 0;
		memset( pPakDir->pszName, 0, nNameLen );
		pPakDir->nNameLen = nNameLen;
	}
	
	pPakDir->nType = DIRTYPE_DIR;
	return 1;
}

int _CheckDir( PPAK_DIR pPakDir )
{
	if( !pPakDir )
		return 0;
	if( !pPakDir->pszName )
		return 0;

	return 1;
}
size_t _GetDirNameLen( PPAK_DIR pPakDir )
{
	size_t nNameLen = 0;

	if( !_CheckDir( pPakDir ) )
		return 0;

	nNameLen = strlen( pPakDir->pszName );
	return nNameLen;
}

size_t _GetDirBufferLen( PPAK_DIR pPakDir )
{
	if( !pPakDir )
		return 0;

	return pPakDir->nNameLen;
}
int _FilterDir( PPAK_DIR pPakDir, DirFilterCallback pfnCallback )
{
	int	bFilter = 1;

	PROCESS_ERROR( pPakDir && pfnCallback );
	bFilter = pfnCallback( pPakDir );

Exit0:
	return bFilter;
}



PPAK_DIR_NODE _GetDirNode( PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnValueDestroy )
{
	PPAK_DIR_NODE pPakNode = 0;

	if ( !pfnValueDestroy || !pfnValueDestroy )
		return pPakNode;

	pPakNode = (PPAK_DIR_NODE)malloc( sizeof(PAK_DIR_NODE) );
	if( !pPakNode )
	{
		//malloc error
		return pPakNode;
	}
	
	if( !_InitDirNode( pPakNode, pfnValueCreator, pfnValueDestroy ) )
	{
		_RecycleDirNode( pPakNode );
		pPakNode = 0;
	}
	return pPakNode;
}

int _InitDirNode( PPAK_DIR_NODE pDirNode, PAK_VALUE_CREATOR pfnValueCreator, PAK_VALUE_DESTROYER pfnValueDestroy )
{
	if( !pDirNode || !pfnValueCreator || !pfnValueDestroy )
	{
		return 0;
	}

	pDirNode->psValue = NULL;
	pDirNode->pfnValueCreator = pfnValueCreator;
	pDirNode->pfnValueDestroy = pfnValueDestroy;
	pDirNode->pParentPakDir = 0;
	pDirNode->pBrotherPakDir = 0;
	pDirNode->pChildPakDir = 0;
	pDirNode->nNodeID = 0;

	pDirNode->psValue = (void*)pDirNode->pfnValueCreator();
	if ( !pDirNode->psValue )
		return 0;
	return 1;
}

int _SetDirNodeName( PPAK_DIR_NODE pDirNode, const char* pszDirName )
{
	if( !pDirNode )
		return 0;
	return _SetDirName( (PPAK_DIR)pDirNode->psValue, pszDirName );
}
int _SetDirNodeType( PPAK_DIR_NODE pDirNode, int nType )
{
	if( !pDirNode )
		return 0;
	return _SetDirType( (PPAK_DIR)pDirNode->psValue, nType );
}

int _SetDirNodeParent( PPAK_DIR_NODE pDirNode, PPAK_DIR_NODE pDirNodeParent )
{
	if( !pDirNode || !pDirNodeParent )
		return 0;

	pDirNode->pParentPakDir = pDirNodeParent;
	pDirNode->pBrotherPakDir = pDirNodeParent->pChildPakDir;
	pDirNodeParent->pChildPakDir = pDirNode;
	return 1;
}

int _AddDirNode( PPAK_DIR_NODE psParentNode, PPAK_DIR_NODE psNode )
{
	if( !psNode || !psParentNode )
		return 0;

	psNode->pParentPakDir = psParentNode;
	psNode->pBrotherPakDir = psParentNode->pChildPakDir;
	psParentNode->pChildPakDir = psNode;
	return 1;
}

int _DeleteDirNode( PPAK_DIR_NODE psNode )
{
	PPAK_DIR_NODE psParent = NULL;
	PPAK_DIR_NODE psDel = NULL;
	PPAK_DIR_NODE psPre = NULL;

	if ( !psNode )
		return 0;

	psParent = psNode->pParentPakDir;
	if ( !psParent ) //Root
		return 1;
	
	psDel = psParent->pChildPakDir;
	psPre = NULL;
	while( psDel )
	{
		if ( psDel == psNode ) //Find
		{
			if ( NULL==psPre ) //First;	
			{
				psParent->pChildPakDir = psDel->pBrotherPakDir;
				psDel->pBrotherPakDir = NULL;
			}
			else
			{
				psPre->pBrotherPakDir = psDel->pBrotherPakDir;
				psDel->pBrotherPakDir = NULL ;
			}
		}
		psPre = psDel;
		psDel = psDel->pBrotherPakDir;
	}

	return 1;
}

int _DestroyDirNodeEx( PPAK_DIR_NODE psDestroy )
{

	PPAK_DIR_NODE psCurNode = NULL;
	PPAK_DIR_NODE psNextNode = NULL;

	psCurNode = psDestroy;
	while ( psCurNode )
	{
		psNextNode = psCurNode->pBrotherPakDir;
		assert( _DestroyDirNode( psCurNode ) );
		psCurNode = psNextNode;
	}
	
	return 1;
}
int _DestroyDirNode( PPAK_DIR_NODE psDestroy )
{
	PPAK_DIR_NODE psChild = NULL;
	PPAK_DIR_NODE PsTemp = NULL;

	if ( !psDestroy )
		return 0;
	
	psChild = psDestroy->pChildPakDir;
	while( psChild )
	{
		PsTemp = psChild->pBrotherPakDir;
		
		assert( _DestroyDirNode( psChild ) );
		
		psChild = PsTemp;
	}
	
	if ( psDestroy->pfnValueDestroy )
	{
		psDestroy->pfnValueDestroy( psDestroy->psValue );
		psDestroy->psValue = NULL;
	}
	free( psDestroy );
	
	return 1;
}

int _SetDirNodeID( PPAK_DIR_NODE pDirNode, size_t nID )
{
	int	bResult = 0;

	PROCESS_ERROR( pDirNode );
	pDirNode->nNodeID = nID;

	bResult = 1;
Exit0:
	return bResult;
}

int _SetDirNodeValue( PPAK_DIR_NODE pDirNode, void* psValue )
{
	int bResult = 0;
	
	PROCESS_ERROR( pDirNode && psValue );
	
	if ( pDirNode->psValue )
	{
		PROCESS_ERROR( pDirNode->pfnValueDestroy );
		pDirNode->pfnValueDestroy( pDirNode->psValue );
		pDirNode->psValue = NULL;
	}
	pDirNode->psValue = psValue;
	bResult = 1;

Exit0:
	return bResult;
}

void* _GetDirNodeValue( PPAK_DIR_NODE pDirNode )
{
	int		bResult = 0;
	void*	psValue	=	NULL;

	PROCESS_ERROR( pDirNode );
	psValue = pDirNode->psValue;

Exit0:
	return psValue;
	
}
int	_GetDirNodeFullName( PPAK_DIR_NODE pPakNode, char* pszPathBuffer, size_t* punPathBufferSize )
{
	int				bResult = 0;
	char*			pszNewPathBuffer = NULL;
	size_t			nNewPathBufferLen = 0;
	size_t			nFullPathLen = 0;

	PROCESS_ERROR( pPakNode && pszPathBuffer && *punPathBufferSize );
	
	nNewPathBufferLen = *punPathBufferSize + 1;
	PROCESS_ERROR( pszNewPathBuffer = (char*)malloc( sizeof(char) * nNewPathBufferLen ) );

	if( !_GetDirNodeFullPath( pPakNode, pszNewPathBuffer, &nNewPathBufferLen ) )
	{
		*punPathBufferSize = nNewPathBufferLen - 1;
		PROCESS_ERROR( 0 );
	}

	nFullPathLen = strlen( pszNewPathBuffer );
	PROCESS_ERROR( nFullPathLen );
	pszNewPathBuffer[nFullPathLen-1] = 0;

	strcpy( pszPathBuffer, pszNewPathBuffer );
	*punPathBufferSize = nFullPathLen;
	bResult = 1;
Exit0:

	if( pszNewPathBuffer )
		free( pszNewPathBuffer );
	return bResult;
}

int	_GetDirNodeFullPath( PPAK_DIR_NODE pPakNode, char* pszPathBuffer, size_t* punPathBufferSize )
{
	int				bResult = 0;
	PPAK_DIR_NODE	pPakNodeCur = NULL;
	char*			pszTempPathBuffer = 0;
	size_t			unRealPathLen = 0;
	size_t			unBufferLen = 0, unLeftBufferLen = 0, unBufferPos = 0;

	PROCESS_ERROR( pPakNode && pszPathBuffer && punPathBufferSize && *punPathBufferSize );
	PROCESS_ERROR( pszTempPathBuffer = (char*)calloc( (*punPathBufferSize), sizeof(char) ) );
	
	pPakNodeCur = pPakNode;
	unBufferLen = (*punPathBufferSize);
	unLeftBufferLen = (*punPathBufferSize);
	unBufferPos = (*punPathBufferSize);

	//Write end character
	unBufferPos--;
	unLeftBufferLen--;
	pszTempPathBuffer[unBufferPos] = 0;
	while( pPakNodeCur )
	{
		size_t unNameLen = 0;
		PPAK_DIR psPakDir = NULL;
		PROCESS_ERROR( psPakDir = (PPAK_DIR)pPakNodeCur->psValue );

		PROCESS_ERROR( psPakDir->pszName );
		unNameLen = strlen( psPakDir->pszName );
		PROCESS_ERROR( unNameLen );

		if( unLeftBufferLen < unNameLen + 1 )
		{
			//Need more memory
			char* pszNewTempPathBuffer = NULL;
			pszNewTempPathBuffer = (char*)realloc( pszTempPathBuffer, unBufferLen + unBufferLen );
			PROCESS_ERROR( pszNewTempPathBuffer );
			pszTempPathBuffer = pszNewTempPathBuffer;

			memcpy( pszTempPathBuffer + unBufferPos + unBufferLen, pszTempPathBuffer + unBufferPos, unBufferLen - unBufferPos );
			unBufferPos += unBufferLen;
			unLeftBufferLen += unBufferLen;
			unBufferLen += unBufferLen;
		}
		if( psPakDir->pszName[unNameLen - 1] != '\\' )
		{
			unBufferPos--;
			unLeftBufferLen--;
			pszTempPathBuffer[unBufferPos] = '\\';
		}
		unBufferPos -= unNameLen;
		unLeftBufferLen -= unNameLen;
		strncpy( pszTempPathBuffer + unBufferPos, psPakDir->pszName, unNameLen );

		pPakNodeCur = pPakNodeCur->pParentPakDir;
	}

	if( unBufferLen - unLeftBufferLen > *punPathBufferSize )
	{
		*punPathBufferSize = unBufferLen - unLeftBufferLen;
		PROCESS_ERROR( 0 );
	}
	
	strcpy( pszPathBuffer, pszTempPathBuffer + unBufferPos );
	*punPathBufferSize = unBufferLen - unLeftBufferLen;
	bResult = 1;
Exit0:

	if( pszTempPathBuffer )
		free( pszTempPathBuffer );
	return bResult;
}

int _RecycleDirNode( PPAK_DIR_NODE pPakNode )
{
	return _DestroyDirNodeEx( pPakNode );
	//PPAK_DIR_NODE pNextBrother = 0;

	//if( !pPakNode )
	//	return 0;
	//
	//if( pPakNode->pChildPakDir )
	//{
	//	_RecycleDirNode( pPakNode->pChildPakDir );
	//}
	//
	//pNextBrother = pPakNode->pBrotherPakDir;
	//
	//if ( pPakNode->pfnValueDestroy )
	//{
	//	if ( !pPakNode->pfnValueDestroy( pPakNode->psValue ) )
	//	{
	//		//Log
	//	}
	//	pPakNode->psValue = NULL;
	//}
	//free( pPakNode );

	//if ( pNextBrother )
	//{
	//	_RecycleDirNode( pNextBrother );
	//}

	//return 1;
}


PPAK_STACK _NewStack()
{
	PPAK_STACK pNewStack = 0;
	pNewStack = (PPAK_STACK)malloc( sizeof(PAK_STACK) );
	if( pNewStack )
	{
		pNewStack->pStackTop = 0;
	}

	return pNewStack;
}
int _DelStack( PPAK_STACK pStack )
{
	PPAK_STACK_ITEM pTop= 0;
	PPAK_STACK_ITEM pTobeDel = 0;
	if( !pStack )
		return 0;
	
	pTop = pStack->pStackTop;
	while( pTop )
	{
		pTobeDel = pTop;
		pTop = pTop->pNext;
		free( pTobeDel );
	}
	free( pStack );
	return 1;
}

int _PushStack( PPAK_STACK pStack, PPAK_STACK_ITEM pItem )
{
	if( !pStack || !pItem )
		return 0;
	if( pItem->pNext )
		return 0;
	
	pItem->pNext = pStack->pStackTop;
	pStack->pStackTop = pItem;
	return 1;
}
PPAK_STACK_ITEM _PopStack( PPAK_STACK pStack )
{
	PPAK_STACK_ITEM pTop = 0;
	if( !pStack )
		return pTop;
	
	pTop = pStack->pStackTop;
	if( pTop )
	{
		pStack->pStackTop = pTop->pNext;
		pTop->pNext = 0;
	}
	return pTop;
}
PPAK_STACK_ITEM _TopStack( PPAK_STACK pStack )
{
	PPAK_STACK_ITEM pTop = 0;
	if( !pStack )
		return pTop;
	return pStack->pStackTop;
}

PPAK_STACK_ITEM _NewStackItem()
{
	PPAK_STACK_ITEM pStackItem = 0;
	pStackItem = ( PPAK_STACK_ITEM )malloc( sizeof(PAK_STACK_ITEM ) );
	if( pStackItem )
	{
		pStackItem->pNext = 0;
		pStackItem->pValue = 0;
		pStackItem->pValueExtra1 = 0;
	}
	return pStackItem;
}
int _DelStackItem( PPAK_STACK_ITEM pStackItem )
{
	if( !pStackItem )
		return 0;

	free( pStackItem );
	return 1;
}

int _RemoveStackItem( PPAK_STACK pStack, PPAK_STACK_ITEM pItem )
{
	int bResult = 0;
	PPAK_STACK_ITEM	pItemTop = NULL, pItemPre = NULL, pItemCur = NULL;
	PPAK_STACK_ITEM pItemTmp = NULL;

	if( !pStack || !pItem || !pStack->pStackTop )
		return 0;

	pItemTop = pItemPre = pStack->pStackTop;
	pItemCur = pStack->pStackTop ? pStack->pStackTop->pNext : NULL;

	if( pItem == pItemTop )
	{
		pItemTmp = pItemTop;
		pStack->pStackTop = pItemTop->pNext;
		pItemTmp->pNext = NULL;
	}
	else
	{
		while( pItemCur )
		{
			if( pItemCur == pItem )
			{
				pItemTmp = pItemCur;
				pItemPre->pNext = pItemCur->pNext;
				pItemTmp->pNext = NULL;
			}
			pItemPre = pItemCur;
			pItemCur = pItemCur->pNext;
		}
	}

	bResult = 1;
	return bResult;
}

int DefaultDirFilter( PPAK_DIR pPakDir )
{
	int	bFilter = 1;

	if( !pPakDir || !pPakDir->pszName )
	{
		bFilter = 0;
		return 0;
	}

	if( 0==strcmp( pPakDir->pszName, "." ) )
		bFilter = 0;
	else if ( 0==strcmp( pPakDir->pszName, ".." ) )
		bFilter = 0;
	else
		bFilter = 1;

	return bFilter;
}
//Last line for linux

